承接上一回[Day 16] 保守型投資 - 「只買不賣」策略真的賺?,
上次提到「只買不賣」策略的報酬率和定存差不多,
然而可能會有人拿著存摺打我臉:「我明明靠這招存到退休金啊? 在唬爛啊!」,
先別急,容我解釋一番,理由很很複雜,這邊先不提了,簡單來說就是我忘了考慮股利。
如果要把股利的因素放進回測裡,最直觀的想法可能是:
「在除息日當天,若有持股,則會在付息日給本金相應的股息」
然而很可惜這招會讓策略忽略的機會成本的概念,打個比方
台積電在2019年6月24日進行了除息,當天股價為241,股息為每股8元
而在上一個交易日6月21日股價為248.5,
乍看之下在6/21買進的股價較高,然而事實上6/24買進雖省下了248.5-241 = 7.5元,
但是卻少賺了股息8元,整體來說還倒賠0.5元。
因此現在的回測分析普遍使用「調整過去股價」的方法,具體作法為:
6/24日股價維持241元,6/21日股價會減去股息,調整後的價格為240.5。
該作法的另一個好處即是讓股價正確反映股票價值,
以更極端的拆分為例:
如果今天公司以0.5的比例拆分股票,
則股價的兩日價差甚至會直接砍半(因為股票數量加倍,但是股本不變),
然而該公司的價值並不會因為股票拆分而砍半,砍半的僅僅是每張的股票價值而已,
如果是用調整股價進行分析,則拆分股票的行為並不會對調整股價有所影響。
url = "https://api.finmindtrade.com/api/v4/data"
parameter = {
"dataset": "TaiwanStockDividend",
"start_date": datetime.datetime(2020, 1, 1, 0, 0).strftime("%Y-%m-%d"),
"end_date": datetime.datetime(2021, 12, 31, 0, 0).strftime("%Y-%m-%d"),
"data_id": stock_index,
}
data = requests.get(url, params=parameter)
data = data.json()
div_df = pd.DataFrame(data["data"])
div_df = div_df[["CashExDividendTradingDate", "CashEarningsDistribution"]]
div_df = div_df.rename({"CashExDividendTradingDate": "date"}, axis=1)
div_df = div_df.rename({"CashEarningsDistribution": "Dividends"}, axis=1)
div_df = div_df.set_index("date")
div_df
date | Dividends |
---|---|
2020-03-19 | 2.50000 |
2020-06-18 | 2.50000 |
2020-09-17 | 2.50000 |
2020-12-17 | 2.50000 |
2021-03-17 | 2.50000 |
2021-06-17 | 2.50000 |
2021-09-16 | 2.75000 |
2021-12-16 | 2.75000 |
調整公式為:
第一次調息因數 = 1 + (股息 / 除息日前一天收盤價)
第一次調整股價 = 除息日原始收盤價 / 第一次調息因數
第二次調息因數 = 第一次調息因數 * (1 + (股息 / 除息日前一天收盤價))
第二次調整股價 = 除息日原始收盤價 / 第二次調息因數
第三次之後的調整以此類推,公式從yahoo finance資料反推而來,
adj_df = etf50[stock_index].join(div_df)
adj_df["F"] = (1 + adj_df["Dividends"] / adj_df["Close"]).shift(-1)
adj_df["Factor"] = adj_df.iloc[::-1]["F"].cumprod().iloc[::-1].bfill().fillna(1)
adj_df["Adj Close"] = adj_df["Close"] / adj_df["Factor"]
adj_df = adj_df.drop(columns=["Dividends", "F", "Factor"]).dropna()
adj_df